package com.spring.framework.context;

import com.spring.framework.annotation.LBAutowired;
import com.spring.framework.annotation.LBController;
import com.spring.framework.annotation.LBService;
import com.spring.framework.beans.BeanDefinition;
import com.spring.framework.beans.BeanPostProcessor;
import com.spring.framework.beans.BeanWrapper;
import com.spring.framework.context.support.BeanDefinitionReader;
import com.spring.framework.core.BeanFactory;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author lb
 * @Title: LBApplicationContext
 * @Description: TODO
 * @date 2018/10/10  15:46
 */
public class LBApplicationContext implements BeanFactory {

    private String [] configLocations;

    private BeanDefinitionReader reader;

    private Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String,BeanDefinition>();

    //用来保证注册式单例的容器
    private Map<String,Object> beanCacheMap = new HashMap<String, Object>();

    //用来存储所有的被代理过得对象
    private Map<String,BeanWrapper> beanWrapperMap = new ConcurrentHashMap<String,BeanWrapper>();

    public LBApplicationContext(String ... configLocations){
        this.configLocations = configLocations;
        refresh();

    }

    public void refresh(){

        //定位
        this.reader = new BeanDefinitionReader(configLocations);


        //加载
        List<String> beanDefinitions = reader.loadBeanDefinitions();
        //注册
        doRegisty(beanDefinitions);
        //依赖注入（lazy-init = false），要执行依赖注入，在这里自动调用getBean()方法
        doAutowired();
    }

    //这里开始执行自动化的依赖注入
    private void doAutowired() {
        for (Map.Entry<String,BeanDefinition> beanDefinitionEntry : this.beanDefinitionMap.entrySet()){
            String beanName = beanDefinitionEntry.getKey();
            if (!beanDefinitionEntry.getValue().isLazyInit()){
                getBean(beanName);
            }
        }
    }


    public void populateBean(String beanName,Object instance){
        Class<?> clazz = instance.getClass();
        //不是所有牛奶都叫特仑苏
        if (!(clazz.isAnnotationPresent(LBController.class)||clazz.isAnnotationPresent(LBService.class))){
            return;
        }
        Field[] fields = clazz.getDeclaredFields();
        for (Field field:fields){
            if (field.isAnnotationPresent(LBAutowired.class)){continue;}
            LBAutowired autowired = field.getAnnotation(LBAutowired.class);
            String autowiredBeanName = autowired.value().trim();
            if ("".equals(autowiredBeanName)){
                autowiredBeanName = field.getType().getName();
            }
            field.setAccessible(true);
            try {
                field.set(instance,this.beanWrapperMap.get(autowiredBeanName).getWrapperInstance() );
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    //真正的将BeanDefinition注册到beanDefinitionMap中
    private void doRegisty(List<String> beanDefinitions) {

        //beanName有三种情况:
        //1、默认是类名首字母小写
        //2、自定义名字
        //3、接口注入
        try{

            for (String className : beanDefinitions){
                Class<?> beanClass = Class.forName(className);

                //如果是一个接口，是不能实例化的
                //用它实现类来实例化
                if (beanClass.isInterface()){continue;}

                BeanDefinition beanDefinition = reader.registerBean(className);
                if (beanDefinition != null){
                    this.beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition );

                }
                Class<?>[] interfaces = beanClass.getInterfaces();
                for (Class<?> i : interfaces){
                    //如果是多个实现类，只能覆盖
                    //为什么？因为Spring没那么智能，就是这么傻
                    //这个时候，可以自定义名字
                    this.beanDefinitionMap.put(i.getName(),beanDefinition );
                }
                //到这里为止，容器初始化完毕

            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    @Override
    public Object getBean(String beanName) {

        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        String beanClassName = beanDefinition.getBeanClassName();
        try {

            //生成通知事件
            BeanPostProcessor beanPostProcessor = new BeanPostProcessor();
            Object instance = instantionBean(beanDefinition);
            if (null == instance) {
                return null;
            }
            //实例化之前调用一次
            beanPostProcessor.postProcessBeforeInitialization(instance,beanName );
            BeanWrapper beanWrapper = new BeanWrapper(instance);
            this.beanWrapperMap.put(beanName,beanWrapper );

            //在实例化之后调用一次
            beanPostProcessor.postProcessAfterInitialization(instance,beanName );

            populateBean(beanName, instance);

            //通过这么已调用就相当于给我们自己留有了操作的空间
            return this.beanWrapperMap.get(beanName).getWrapperInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    //传一个BeanDefinition，就返回一个实例bean
    private Object instantionBean(BeanDefinition beanDefinition){

        Object instance;
        String beanClassName = beanDefinition.getBeanClassName();
        try {
            //因为根据class才能确定一个类是否有实例
            if (this.beanCacheMap.containsKey(beanClassName)){
                instance = this.beanCacheMap.get(beanClassName);
            }else{
                Class<?> clazz = Class.forName(beanClassName);
                instance = clazz.newInstance();
                this.beanCacheMap.put(beanClassName,instance );

            }
            return instance;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
